home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
c
/
nos042_s
/
zm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-09-16
|
24KB
|
1,063 lines
/****************************************************************************
* Language : Turbo C 2.0 *
* Logfile : zm.c *
* Project : Comms Library. *
* Date : 25 Jan 90 *
* Revision : 1.1 GT PC version. *
* 25 Oct 92 : 1.2 GT KA9Q mods. *
*****************************************************************************
* Purpose : ZMODEM protocol primitives. *
*****************************************************************************
* : This module is based on the equivalent module in the *
* : 31 Aug 87 version of rz/sz. *
* $Id: zm.c 1.1 93/01/16 18:38:59 ROOT_DOS Exp $
****************************************************************************/
/*
* Z M . C
* ZMODEM protocol primitives
* 07-28-87 Chuck Forsberg Omen Technology Inc
*
* Entry point Functions:
* _zsbhdr (type, hdr) send binary header
* _zshhdr (type, hdr) send hex header
* _zgethdr (hdr, eflag) receive header - binary or hex
* _zsdata (buf, len, frameend) send data
* _zrdata (buf, len) receive data
* _stohdr (pos) store position data in _Txhdr
* long _rclhdr (hdr) recover position offset from header
*/
#ifndef CANFDX
#include "zmodem.h"
int _Rxtimeout = 100; /* Tenths of seconds to wait for something */
#endif
#include <setjmp.h>
#include "config.h"
#include "sz.h"
#include "zm.h"
#include "rbsb.h"
#ifndef UNSL
#define UNSL unsigned
#endif
/****************************************************************************
* Local prototypes. *
****************************************************************************/
static int noxrd7 (void);
static int zdlread (void);
static int zgeth1 (void);
static int zgethex (void);
static void zputhex (int c);
static int zrbhdr (char *hdr);
static int zrbhdr32 (char *hdr);
static int zrdat32 (char *buf, int length);
static int zrhhdr (char *hdr);
static void zsbh32 (char *hdr, int type);
static void zsda32 (char *buf, int length, int frameend);
static void zsendline (int c);
/****************************************************************************
* Globals used by ZMODEM functions. *
****************************************************************************/
static int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
static int Rxtype; /* Type of header received */
int _Rxcount; /* Count of data bytes received */
char _Rxhdr[4]; /* Received header */
char _Txhdr[4]; /* Transmitted header */
long _Rxpos; /* Received file position */
long _Txpos; /* Transmitted file position */
int _Txfcs32; /* TRUE - send binary frames with 32 bit FCS */
int _Crc32t; /* Display flag - 32 bit CRC being sent */
int _Crc32; /* Display flag - 32 bit CRC being received */
int _Znulls; /* No of nulls to send at start of ZDATA hdr */
char _Attn[ZATTNLEN + 1]; /* Attention string rx sends to tx on err */
static char *frametypes[] =
{
"Carrier Lost", /* -3 */
"TIMEOUT", /* -2 */
"ERROR", /* -1 */
#define FTOFFSET 3
"ZRQINIT",
"ZRINIT",
"ZSINIT",
"ZACK",
"ZFILE",
"ZSKIP",
"ZNAK",
"ZABORT",
"ZFIN",
"ZRPOS",
"ZDATA",
"ZEOF",
"ZFERR",
"ZCRC",
"ZCHALLENGE",
"ZCOMPL",
"ZCAN",
"ZFREECNT",
"ZCOMMAND",
"ZSTDERR",
"xxxxx"
#define FRTYPES 22 /* Total number of frame types in this array */
/* not including psuedo negative entries */
};
/****************************************************************************
* _zsbhdr *
* Send ZMODEM binary header <hdr> of type <type>. *
****************************************************************************/
void _zsbhdr (int type, char *hdr)
{
int n;
unsigned short crc;
_vfile ("_zsbhdr: %s %lx", frametypes[type + FTOFFSET], _rclhdr (hdr));
if (type == ZDATA)
for (n = _Znulls; --n >= 0;)
zsendline (0);
_xsendline (ZPAD);
_xsendline (ZDLE);
if ((_Crc32t = _Txfcs32) != 0)
zsbh32 (hdr, type);
else
{
_xsendline (ZBIN);
zsendline (type);
crc = updcrc (type, 0);
for (n = 4; --n >= 0; ++hdr)
{
zsendline (*hdr);
crc = updcrc ((0377 & *hdr), crc);
}
crc = updcrc (0, updcrc (0, crc));
zsendline (crc >> 8);
zsendline (crc);
}
if (type != ZDATA)
_flushmo ();
} /* void _zsbhdr (int type, char *hdr) */
/****************************************************************************
* zsbh32 *
* Send ZMODEM binary header <hdr> of type <type>. *
****************************************************************************/
static void zsbh32 (char *hdr, int type)
{
int n;
UNSL long crc;
_xsendline (ZBIN32);
zsendline (type);
crc = 0xFFFFFFFFL;
#ifdef DEBUGZ
_vfile ("\n%s:%d zsbh32 initial CRC = %08lx", __FILE__, __LINE__, crc);
#endif
crc = UPDC32 (type, crc);
#ifdef DEBUGZ
_vfile ("%s:%d zsbh32 byte = %x, CRC = %08lx", __FILE__, __LINE__,
type, crc);
#endif
for (n = 4; --n >= 0; ++hdr)
{
crc = UPDC32 ((0377 & *hdr), crc);
#ifdef DEBUGZ
_vfile ("%s:%d zsbh32 byte = %x, CRC = %08lx", __FILE__, __LINE__,
(0377 & *hdr), crc);
#endif
zsendline (*hdr);
}
crc = ~crc;
#ifdef DEBUGZ
_vfile ("%s:%d zsbh32 sent CRC = %08lx", __FILE__, __LINE__, crc);
#endif
for (n = 4; --n >= 0;)
{
zsendline ((int) crc);
crc >>= 8;
}
} /* static void zsbh32 (char *hdr, int type) */
/****************************************************************************
* _zshhdr *
* Send ZMODEM HEX header <hdr> of type <type>. *
****************************************************************************/
void _zshhdr (int type, char *hdr)
{
int n;
unsigned short crc;
_vfile ("_zshhdr: %s %lx", frametypes[type + FTOFFSET], _rclhdr (hdr));
_sendline (ZPAD);
_sendline (ZPAD);
_sendline (ZDLE);
_sendline (ZHEX);
zputhex (type);
_Crc32t = 0;
crc = updcrc (type, 0);
for (n = 4; --n >= 0; ++hdr)
{
zputhex (*hdr);
crc = updcrc ((0377 & *hdr), crc);
}
crc = updcrc (0, updcrc (0, crc));
zputhex (crc >> 8);
zputhex (crc);
/* Make it printable on remote machine */
_sendline (015);
_sendline (012);
/* Uncork the remote in case a fake XOFF has stopped data flow. */
if (type != ZFIN && type != ZACK)
_sendline (021);
_flushmo ();
} /* void _zshhdr (int type, char *hdr) */
/****************************************************************************
* _zsdata *
* Send binary array <buf> of length <length>, with ending ZDLE sequence *
* <frameend>. *
****************************************************************************/
void _zsdata (char *buf, int length, int frameend)
{
unsigned short crc;
_vfile ("_zsdata: length=%d end=%x", length, frameend);
if (_Crc32t)
zsda32 (buf, length, frameend);
else
{
crc = 0;
for (;--length >= 0; ++buf)
{
zsendline (*buf);
crc = updcrc ((0377 & *buf), crc);
}
_xsendline (ZDLE);
_xsendline (frameend);
crc = updcrc (frameend, crc);
crc = updcrc (0, updcrc (0, crc));
zsendline (crc >> 8);
zsendline (crc);
}
if (frameend == ZCRCW)
{
_xsendline (XON);
_flushmo ();
}
} /* void _zsdata (char *buf, int length, int frameend) */
/****************************************************************************
* zsda32 *
* Send <length> bytes from <buf> followed by ZDLE <frameend> with a 32 *
* bit CRC. *
****************************************************************************/
static void zsda32 (char *buf, int length, int frameend)
{
UNSL long crc;
crc = 0xFFFFFFFFL;
#ifdef DEBUGZ
_vfile ("\n%s:%d zsda32 initial CRC = %08lx", __FILE__, __LINE__, crc);
#endif
for (;--length >= 0; ++buf)
{
crc = UPDC32 ((0377 & *buf), crc);
#if 0
_vfile ("%s:%d zsda32 byte = %x, CRC = %08lx", __FILE__, __LINE__,
(0377 & *buf), crc);
#endif
zsendline (*buf);
}
_xsendline (ZDLE);
_xsendline (frameend);
crc = UPDC32 (frameend, crc);
#ifdef DEBUGZ
_vfile ("%s:%d zsda32 byte = %x, CRC = %08lx", __FILE__, __LINE__,
frameend, crc);
#endif
crc = ~crc;
#ifdef DEBUGZ
_vfile ("%s:%d zsda32 sent CRC = %08lx", __FILE__, __LINE__, crc);
#endif
for (length = 4; --length >= 0;)
{
zsendline ((int) crc);
crc >>= 8;
}
} /* static void zsda32 (char *buf, int length, int frameend) */
/****************************************************************************
* _zrdata *
* Receive array <buf> of max <length> with ending ZDLE sequence and CRC. *
* Returns the ending character or error code. NB: On errors may store *
* <length> + 1 bytes! *
****************************************************************************/
int _zrdata (char *buf, int length)
{
int c;
unsigned short crc;
char *end;
int d;
if (Rxframeind == ZBIN32)
return zrdat32 (buf, length);
crc = _Rxcount = 0;
end = buf + length;
while (buf <= end)
{
if ((c = zdlread ()) & ~0377)
{
crcfoo:
switch (c)
{
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
crc = updcrc (((d = c) & 0377), crc);
if ((c = zdlread ()) & ~0377)
goto crcfoo;
crc = updcrc (c, crc);
if ((c = zdlread ()) & ~0377)
goto crcfoo;
crc = updcrc (c, crc);
if (crc & 0xFFFF)
{
_zperr_ ("Bad data CRC");
return ERROR;
}
_Rxcount = (int) (length - (end - buf));
_vfile ("_zrdata: cnt = %d ret = %x", _Rxcount, d);
return d;
case GOTCAN:
_zperr_ ("Sender cancelled");
return ZCAN;
case ZTIMEOUT:
_zperr_ ("TIMEOUT");
return c;
default:
_zperr_ ("Bad data subpacket");
return c;
} /* switch (c) */
} /* if ((c = zdlread ()) & ~0377) */
*buf++ = (char) c;
crc = updcrc (c, crc);
} /* while (buf <= end) */
_zperr_ ("Data subpacket too long");
return ERROR;
} /* int _zrdata (char *buf, int length) */
/****************************************************************************
* zrdat32 *
* As _zrdata with 32 bit CRC. *
****************************************************************************/
static int zrdat32 (char *buf, int length)
{
int c;
UNSL long crc;
char *end;
int d;
crc = 0xFFFFFFFFL;
_Rxcount = 0;
end = buf + length;
while (buf <= end)
{
if ((c = zdlread ()) & ~0377)
{
crcfoo:
switch (c)
{
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
d = c;
c &= 0377;
crc = UPDC32 (c, crc);
if ((c = zdlread ()) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if ((c = zdlread ()) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if ((c = zdlread ()) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if ((c = zdlread ()) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if (crc != 0xDEBB20E3L)
{
_zperr_ ("Bad data CRC");
return ERROR;
}
_Rxcount = (int) (length - (end - buf));
_vfile ("zrdat32: cnt = %d ret = %x", _Rxcount, d);
return d;
case GOTCAN:
_zperr_ ("Sender cancelled");
return ZCAN;
case ZTIMEOUT:
_zperr_ ("TIMEOUT");
return c;
default:
_zperr_ ("Bad data subpacket");
return c;
} /* switch (c) */
} /* if ((c = zdlread ()) & ~0377) */
*buf++ = (char) c;
crc = UPDC32 (c, crc);
} /* while (buf <= end) */
_zperr_ ("Data subpacket too long");
return ERROR;
} /* static int zrdat32 (char *buf, int length) */
/****************************************************************************
* _zgethdr *
* Read a ZMODEM header to <hdr>, either binary or hex. <eflag> controls *
* local display of non zmodem characters: *
* 0: no display *
* 1: display printing characters only *
* 2: display all non ZMODEM characters *
* On success, set Zmodem to 1, set _Rxpos and return type of header. *
* Otherwise return negative on error. *
* Return ERROR instantly if ZCRCW sequence, for fast error recovery. *
****************************************************************************/
int _zgethdr (char *hdr, int eflag)
{
int c, n, cancount;
n = _Zrwindow + _Baud_z; /* Max bytes before start of frame */
Rxframeind = Rxtype = 0;
startover:
cancount = 5;
again:
/* Return immediate ERROR if ZCRCW sequence seen */
switch (c = _readline (_Rxtimeout))
{
case RCDO:
case ZTIMEOUT:
goto fifi;
case CAN:
gotcan:
if (--cancount <= 0)
{
c = ZCAN;
goto fifi;
}
switch (c = _readline (1))
{
case ZTIMEOUT:
goto again;
case ZCRCW:
c = ERROR;
/* **** FALL THRU TO **** */
case RCDO:
goto fifi;
default:
break;
case CAN:
if (--cancount <= 0)
{
c = ZCAN;
goto fifi;
}
goto again;
} /* switch (c = _readline (1)) */
/* **** FALL THRU TO **** */
default:
agn2:
if (--n == 0)
{
_zperr_ ("Garbage count exceeded");
return (ERROR);
}
if (eflag && ((c &= 0177) & 0140))
_bttyout (c);
else if (eflag > 1)
_bttyout (c);
goto startover;
case ZPAD | 0200: /* This is what we want. */
case ZPAD: /* This is what we want. */
break;
} /* switch (c = _readline (_Rxtimeout)) */
cancount = 5;
splat:
switch (c = noxrd7 ())
{
case ZPAD:
goto splat;
case RCDO:
case ZTIMEOUT:
goto fifi;
default:
goto agn2;
case ZDLE: /* This is what we want. */
break;
} /* switch (c = noxrd7 ()) */
switch (c = noxrd7 ())
{
case RCDO:
case ZTIMEOUT:
goto fifi;
case ZBIN:
Rxframeind = ZBIN;
_Crc32 = FALSE;
c = zrbhdr (hdr);
break;
case ZBIN32:
_Crc32 = Rxframeind = ZBIN32;
c = zrbhdr32 (hdr);
break;
case ZHEX:
Rxframeind = ZHEX;
_Crc32 = FALSE;
c = zrhhdr (hdr);
break;
case CAN:
goto gotcan;
default:
goto agn2;
} /* switch (c = noxrd7 ()) */
_Rxpos = hdr[ZP3] & 0377;
_Rxpos = (_Rxpos << 8) + (hdr[ZP2] & 0377);
_Rxpos = (_Rxpos << 8) + (hdr[ZP1] & 0377);
_Rxpos = (_Rxpos << 8) + (hdr[ZP0] & 0377);
fifi:
switch (c)
{
case GOTCAN:
c = ZCAN;
/* **** FALL THRU TO **** */
case ZNAK:
case ZCAN:
case ERROR:
case ZTIMEOUT:
case RCDO:
_zperr_ ("Got %s", frametypes[c + FTOFFSET]);
/* **** FALL THRU TO **** */
default:
if (c >= -3 && c <= FRTYPES)
_vfile ("_zgethdr: %s %lx", frametypes[c + FTOFFSET], _Rxpos);
else
_vfile ("_zgethdr: %d %lx", c, _Rxpos);
} /* switch (c) */
return c;
} /* int _zgethdr (char *hdr, int eflag) */
/****************************************************************************
* zrbhdr *
* Receive a binary style header (type and position). *
****************************************************************************/
static int zrbhdr (char *hdr)
{
int c, n;
unsigned short crc;
if ((c = zdlread ()) & ~0377)
return c;
Rxtype = c;
crc = updcrc (c, 0);
for (n = 4; --n >= 0; ++hdr)
{
if ((c = zdlread ()) & ~0377)
return c;
crc = updcrc (c, crc);
*hdr = (char) c;
}
if ((c = zdlread ()) & ~0377)
return c;
crc = updcrc (c, crc);
if ((c = zdlread ()) & ~0377)
return c;
crc = updcrc (c, crc);
if (crc & 0xFFFF)
{
_zperr_ ("Bad Header CRC");
return ERROR;
}
_Zmodem = 1;
return Rxtype;
} /* static int zrbhdr (char *hdr) */
/****************************************************************************
* zrbhdr32 *
* Receive a binary style header (type and position) with 32 bit FCS. *
****************************************************************************/
static int zrbhdr32 (char *hdr)
{
int c, n;
UNSL long crc;
if ((c = zdlread ()) & ~0377)
return c;
Rxtype = c;
crc = 0xFFFFFFFFL;
crc = UPDC32 (c, crc);
#ifdef DEBUGZ
_vfile ("zrbhdr32 c=%X crc=%lX", c, crc);
#endif
for (n = 4; --n >= 0; ++hdr)
{
if ((c = zdlread ()) & ~0377)
return c;
crc = UPDC32 (c, crc);
*hdr = (char) c;
#ifdef DEBUGZ
_vfile ("zrbhdr32 c=%X crc=%lX", c, crc);
#endif
}
for (n = 4; --n >= 0;)
{
if ((c = zdlread ()) & ~0377)
return c;
crc = UPDC32 (c, crc);
#ifdef DEBUGZ
_vfile ("zrbhdr32 c=%X crc=%lX", c, crc);
#endif
}
if (crc != 0xDEBB20E3L)
{
_zperr_ ("Bad Header CRC"); return ERROR;
}
_Zmodem = 1;
return Rxtype;
} /* static int zrbhdr32 (char *hdr) */
/****************************************************************************
* zrhhdr *
* Receive a hex style header (type and position). *
****************************************************************************/
static int zrhhdr (char *hdr)
{
int c;
unsigned short crc;
int n;
if ((c = zgethex ()) < 0)
return c;
Rxtype = c;
crc = updcrc (c, 0);
for (n = 4; --n >= 0; ++hdr)
{
if ((c = zgethex ()) < 0)
return c;
crc = updcrc (c, crc);
*hdr = (char) c;
}
if ((c = zgethex ()) < 0)
return c;
crc = updcrc (c, crc);
if ((c = zgethex ()) < 0)
return c;
crc = updcrc (c, crc);
if (crc & 0xFFFF)
{
_zperr_ ("Bad Header CRC");
return ERROR;
}
if (_readline (1) == '\r') /* Throw away possible cr/lf */
_readline (1);
_Zmodem = 1;
return Rxtype;
} /* static int zrhhdr (char *hdr) */
/****************************************************************************
* zputhex *
* Send a byte as two hex digits. *
****************************************************************************/
static void zputhex (int c)
{
static char digits[] = "0123456789abcdef";
if (_Verbose > 8)
_vfile ("zputhex: %02X", c);
_sendline (digits[(c & 0xF0) >> 4]);
_sendline (digits[(c) & 0xF]);
} /* static void zputhex (int c) */
/****************************************************************************
* zsendline *
* Send character <c> with ZMODEM escape sequence encoding. Escape XON, *
* XOFF. Escape CR following @ (Telenet net escape). *
****************************************************************************/
static void zsendline (int c)
{
static int lastsent;
switch (c &= 0377)
{
case ZDLE:
_xsendline (ZDLE);
_xsendline (lastsent = (c ^= 0100));
break;
case 015:
case 0215:
if (!_Zctlesc && (lastsent & 0177) != '@')
goto sendit;
/* **** FALL THRU TO **** */
case 020:
case 021:
case 023:
case 0220:
case 0221:
case 0223:
_xsendline (ZDLE);
c ^= 0100;
sendit:
_xsendline (lastsent = c);
break;
default:
if (_Zctlesc && ! (c & 0140))
{
_xsendline (ZDLE);
c ^= 0100;
}
_xsendline (lastsent = c);
} /* switch (c &= 0377) */
} /* static void zsendline (int c) */
/****************************************************************************
* zgethex, zgeth1 *
* Decode two lower case hex digits into an 8 bit byte value. *
****************************************************************************/
static int zgethex (void)
{
int c;
c = zgeth1 ();
if (_Verbose > 8)
_vfile ("zgethex: %02X", c);
return c;
} /* static int zgethex (void) */
static int zgeth1 (void)
{
int c, n;
if ((c = noxrd7 ()) < 0)
return c;
n = c - '0';
if (n > 9)
n -= ('a' - ':');
if (n & ~0xF)
return ERROR;
if ((c = noxrd7 ()) < 0)
return c;
c -= '0';
if (c > 9)
c -= ('a' - ':');
if (c & ~0xF)
return ERROR;
c += (n << 4);
return c;
} /* static int zgeth1 (void) */
/****************************************************************************
* zdlread *
* Read a byte, checking for ZMODEM escape encoding including CAN * 5 *
* which represents a quick abort. *
****************************************************************************/
static int zdlread (void)
{
int c;
again:
switch (c = _readline (_Rxtimeout))
{
case ZDLE:
break;
case 023:
case 0223:
case 021:
case 0221:
goto again;
default:
if (_Zctlesc && !(c & 0140))
{
goto again;
}
return c;
} /* switch (c = _readline (_Rxtimeout)) */
again2:
if ((c = _readline (_Rxtimeout)) < 0)
return c;
if (c == CAN && (c = _readline (_Rxtimeout)) < 0)
return c;
if (c == CAN && (c = _readline (_Rxtimeout)) < 0)
return c;
if (c == CAN && (c = _readline (_Rxtimeout)) < 0)
return c;
switch (c)
{
case CAN:
return GOTCAN;
case ZCRCE:
case ZCRCG:
case ZCRCQ:
case ZCRCW:
return (c | GOTOR);
case ZRUB0:
return 0177;
case ZRUB1:
return 0377;
case 023:
case 0223:
case 021:
case 0221:
goto again2;
default:
if (_Zctlesc && ! (c & 0140))
{
goto again2;
}
if ((c & 0140) == 0100)
return (c ^ 0100);
break;
} /* switch (c) */
_zperr_ ("Bad escape sequence %x", c);
return ERROR;
} /* static int zdlread (void) */
/****************************************************************************
* noxrd7 *
* Read a character from the modem line with timeout. Eat parity, XON *
* and XOFF characters. *
****************************************************************************/
static int noxrd7 (void)
{
int c;
for (;;)
{
if ((c = _readline (_Rxtimeout)) < 0)
return c;
switch (c &= 0177)
{
case XON:
case XOFF:
continue;
default:
if (_Zctlesc && !(c & 0140))
continue;
case '\r':
case '\n':
case ZDLE:
return c;
} /* switch (c &= 0177) */
} /* for (;;) */
} /* static int noxrd7 (void) */
/****************************************************************************
* _stohdr *
* Store long integer pos in _Txhdr. *
****************************************************************************/
void _stohdr (long pos)
{
_Txhdr[ZP0] = (char) pos;
_Txhdr[ZP1] = (char) (pos >> 8);
_Txhdr[ZP2] = (char) (pos >> 16);
_Txhdr[ZP3] = (char) (pos >> 24);
} /* void _stohdr (long pos) */
/****************************************************************************
* _rclhdr *
* Recover a long integer from a header. *
****************************************************************************/
long _rclhdr (char *hdr)
{
long l;
l = (hdr[ZP3] & 0377);
l = (l << 8) | (hdr[ZP2] & 0377);
l = (l << 8) | (hdr[ZP1] & 0377);
l = (l << 8) | (hdr[ZP0] & 0377);
return l;
} /* long _rclhdr (char *hdr) */
/* End of zm.c */